/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package z.h.w.jar.data.time.period;

import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import z.h.w.jar.arithmetic.Sort;
import z.h.w.jar.arithmetic.method.SortShell;
import z.h.w.jar.data.time.Attr;
import z.h.w.jar.data.time.Place;
import z.h.w.jar.data.time.PlaceAct;
import z.h.w.jar.data.time.Time;
import z.h.w.jar.data.time.Unit;
import z.h.w.jar.kit.method.Num;
import z.h.w.jar.kit.method.To;

/**
 *
 */
public class Period extends AbstractPeriod {

   public Period ( Date start , Date end ) {
      super ( start , end );
   }

   /**
    *
    * @param multiple unit
    * @param unit
    */
   public Period ( Double multiple , Unit unit ) {
      super ( multiple , unit );
   }

   /**
    *
    * @param time1 time2
    * @param time2
    */
   public Period ( String time1 , String time2 ) {
      super ( time1 , time2 );
   }

   /**
    *
    * @param start end
    * @param end
    */
   public Period ( Time start , Time end ) {
      super ( start , end );
   }

   public static Period born ( Time time1 , Time time2 ) {
      return new Period ( time1 , time2 );
   }

   public static Period born ( Date time1 , Date time2 ) {
      return new Period ( time1 , time2 );
   }

   public static Period born ( Double arg , Unit unit ) {
      return new Period ( arg / 2 , unit );
   }

   /**
    * 为了应付知道其实日子，但是结束日是像是3周，或者3个月之后的某一天
    * @param start
    *
    * @param arg
    * @param unit
    * @return
    */
   public static Period born ( String start , Double arg , Unit unit ) {
      Time time = To.string2Time ( start );
      return born ( time , time.offset ( arg , unit ) );
   }

   /**
    * 为了应付知道其实日子，但是结束日是像是3周外加2天，单位不同的运算
    * @param start
    * @param arg
    * @return
    */
   public static Period born ( String start , Double... arg ) {
      Double sum = Num.sum ( arg );
      return born ( start , sum , Unit.MILLISECOND );
   }

   public static Period born ( String start , String end ) {
      return new Period ( start , end );
   }

   @Override
   public Period expand ( AbstractPeriod period ) {
      List<Time> list = this.toList ();
      list.addAll ( period.toList () );
      int len = list.size ();
      Time[] sorted = new Time[ len ];
      for ( int x = 0 ; x < len ; x ++ ) {
         sorted[x] = list.get ( x );
      }
      sorted = Sort.sort ( sorted , new SortShell () );
      return new Period ( sorted[0] , sorted[3] );
   }

   @Override
   public Period offset ( Double multiple , Unit unit ) {
      Time b = this.getStart ().offset ( multiple , unit );
      Time e = this.getEnd ().offset ( multiple , unit );
      return new Period ( b , e );
   }

   @Override
   public Double to ( Unit unit ) {
      Long ms = this.getTime ();
      return ms / unit.convert ( 1.0 );
   }

   @Override
   public Map<Time , String> tell ( Attr attr ) {
//      return attr.getFields( this );
      return null;
   }

   /**
    * multiple平均分为多少段，margin时间间距，间距单位
    */
   @Override
   public Period[] split ( Double multiple , Double margin , Unit unit ) {
      List<Period> re = new LinkedList<> ();
      if ( multiple == 1.0 ) {
         re.add ( this );
      } else {
         //求出单位段
         Double ogniLen = this.getTime () / multiple;
         Time start = this.getStart ();
         Time end;
         while ( true ) {
            end = start.offset ( ogniLen , Unit.MILLISECOND );
            if ( end.is ( Place.RIGHT , this.getEnd () ) ) {
               re.add ( Period.born ( start , this.getEnd () ) );
               break;
            }
            re.add ( Period.born ( start , end ) );
            start = end.offset ( margin , unit );
         }
      }
      return To.list2Array ( re );
   }

   public Period[] split ( Double multiple , Double mileseconde ) {
      List<Period> re = new LinkedList<> ();
      if ( multiple == 1.0 ) {
         re.add ( this );
      } else {
         //求出单位段
         Double ogniLen = this.getTime () / multiple;
         Time start = this.getStart ();
         Time end;
         while ( true ) {
            end = start.offset ( ogniLen , Unit.MILLISECOND );
            if ( end.is ( Place.RIGHT , this.getEnd () ) ) {
               re.add ( Period.born ( start , this.getEnd () ) );
               break;
            }
            re.add ( Period.born ( start , end ) );
            start = end.offset ( mileseconde , Unit.MILLISECOND );
         }
      }
      return To.list2Array ( re );
   }

   /**
    *
    * @param place time
    * <p/>
    * @param time
    *
    * @return
    */
   @Override
   public Boolean is ( Place place , Time time ) {
      PlaceAct placeAct = new PlaceAct ();
      return placeAct.place ( time , this , place );
   }

   /**
    *
    * @param bma
    *
    * @return
    */
   @Override
   public Boolean is ( Place bma , Period period ) {
      PlaceAct placeAct = new PlaceAct ();
      return placeAct.place ( period , this , bma );
   }

   @Override
   public Boolean is ( Place place , Date date ) {
      PlaceAct placeAct = new PlaceAct ();
      return placeAct.place ( Time.born ( date ) , this , place );
   }

}
